import os
import jinja2

# # import googletrans
# from translate import Translator

from utils.file_util import FileUtil

from uml.uml_manager import UmlManager
from model.uml_model import UmlModel
from model.uml_property import UmlProperty
from .gen_context import GenContext
from .gen_module import GenModule


class QtPropProviderGenerator:
    property_providers = ["Class", "State", "TimeEvent", "OpaqueBehavior", "Deployment"]

    def __init__(self, model: UmlModel, output_path: str) -> None:
        self.output_path = output_path
        self.model = model
        self.providers: dict[str, str] = {}
        self.attributes: dict[str, UmlProperty] = {}
        # self.translator = Translator(from_lang="english", to_lang="chinese")
        # print(self.translator.translate("Good night!"))

        self.env = jinja2.Environment(
            trim_blocks=True,
            lstrip_blocks=True,
            keep_trailing_newline=True,
            loader=jinja2.FileSystemLoader(FileUtil.get_path("gen/templates/qt_prop")),
        )
        self.env.globals["get_init_statement"] = self.__get_init_statement
        self.env.globals["get_value_changes_string"] = self.__get_value_changes_string
        self.env.globals["get_value_changes_bool"] = self.__get_value_changes_bool
        self.env.globals["get_value_changes_int"] = self.__get_value_changes_int
        self.env.globals["get_value_changes_double"] = self.__get_value_changes_double

    def gen(self) -> None:
        self.__collect_property_providers()
        for provider in self.providers:
            self.__gen_code(provider)

    def __gen_code(self, name: str) -> None:
        self.attributes = {}
        self.__collect_class_attributes(name)
        self.attributes = {k: self.attributes[k] for k in sorted(self.attributes)}

        params: dict = {"model": self.model, "entity": self.model.classes[name]}

        context: GenContext = GenContext(self.output_path)
        context.modules.append(
            GenModule(
                "providerClass.cpp",
                "providerClass.cpp.j2",
                f"Provider{name}.cpp",
            )
        )
        context.modules.append(
            GenModule(
                "providerClass.h",
                "providerClass.h.j2",
                f"Provider{name}.h",
            ),
        )

        for module in context.modules:
            template = self.env.get_template(module.template)
            FileUtil.write_text_file_if_change(
                os.path.join(FileUtil.get_path(context.root), module.output_path),
                template.render(params),
            )

    def __collect_property_providers(self):
        """
        - 收集类的列表属性，将列表属性的类加入属性提供类列表中。
        """
        self.providers = {}

        need_classes = {}

        for provider in QtPropProviderGenerator.property_providers:
            self.providers[provider] = f"{provider}.this"
            need_classes[provider] = provider

        while len(need_classes) > 0:
            provider = list(need_classes.keys())[0]
            # 刪除处理过的类
            need_classes.pop(provider, None)
            clazz = self.model.classes.get(provider)
            if clazz is None:
                continue
            for attr in clazz.ownedAttributes:
                type_name = attr.type.href
                if (
                    type_name not in self.providers.keys()
                    and type_name.find("PrimitiveTypes") == -1
                    and self.model.enums.get(type_name) is None
                ):
                    self.providers[type_name] = f"{provider}.{attr.name}"
                    need_classes[type_name] = type_name

    def __collect_class_attributes(self, name: str):
        """
        - 收集类的基本属性。
        """

        clazz = self.model.classes.get(name)
        if clazz is None:
            return

        for attr in clazz.ownedAttributes:
            if attr.name not in self.attributes and (
                UmlManager.get_attr_is_primitive(attr)
                or UmlManager.get_attr_is_enum(attr, self.model)
            ):
                self.attributes[attr.name] = attr

        for general in clazz.generalizations:
            self.__collect_class_attributes(general.general)

    def __get_init_statement(self) -> str:
        """
        - InitEditor 语句。
        """
        text = ""
        for attr in self.attributes.values():
            translation = self.trans(attr.name)
            attr_name = UmlManager.get_attr_identity(attr)
            if UmlManager.get_attr_is_enum(attr, self.model):
                text += f"    QStringList {attr_name}Names;\n"
                enum = UmlManager.get_attr_enum(attr, self.model)
                for item in enum.ownedLiterals:
                    text += f'    {attr_name}Names.append("{item.name}");\n'
                text += f'    addProperty("{attr_name}", "{translation}", static_cast<int>(entity_->{attr_name}()), {attr_name}Names);\n'
            else:
                text += f'    addProperty("{attr_name}", "{translation}", entity_->{attr_name}());\n'
        return text
        #     property = enumManager->addProperty("测量类型");
        # while (!Types.isEmpty())
        # {
        #     Types.clear();
        # }
        # Types << "进气凸轮" << "排气凸轮" << "喷油凸轮" << "信号轮";//重新赋予新值

        # enumManager->setEnumNames(property, Types);

    def __get_value_changes_string(self) -> str:
        return self.__get_value_changes("QString")

    def __get_value_changes_bool(self) -> str:
        return self.__get_value_changes("bool")

    def __get_value_changes_int(self) -> str:
        return self.__get_value_changes("int")

    def __get_value_changes_double(self) -> str:
        return self.__get_value_changes("double")

    def __get_value_changes(self, type: str) -> str:
        """
        - onValueChanges(QString)。
        """
        # self.attributes.sort(key=lambda x: x.name)
        text = ""
        for attr in self.attributes.values():
            attr_type = UmlManager.get_attr_type(attr, self.model)
            attr_name = UmlManager.get_attr_identity(attr)
            if attr_type != type and not (
                type == "int" and UmlManager.get_attr_is_enum(attr, self.model)
            ):
                continue
            if len(text) > 0:
                text += " else "
            else:
                text += ""
            text += f'if (id == "{attr_name}") {{\n'
            if UmlManager.get_attr_is_enum(attr, self.model):
                text += f"        entity_->{self.get_setter_name(attr_name)}(static_cast<{attr_type}>(value));\n"
                text += f"        emit appSignals->onElementChanged(this, entity_);\n"
            else:
                text += f"        entity_->{self.get_setter_name(attr_name)}(value);\n"
                if attr_name == "name":
                    text += f"        emit appSignals->onElementRenamed(this, entity_);\n"
                else:
                    text += f"        emit appSignals->onElementChanged(this, entity_);\n"
            text += "    }"
        return text

    def get_setter_name(self, field: str) -> str:
        return "set" + field[0].upper() + field[1:]

    def trans(self, text: str) -> str:
        translation = text
        # try:
        #     new_text = ""
        #     for char in text:
        #         if char >= "A" and char <= "Z":
        #             new_text += " "
        #         new_text += char
        #     translation = self.translator.translate(new_text)
        #     print(new_text, translation)
        # except:
        #     pass
        return translation
